﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Net;
using System.Threading;

namespace GMusicBox.Core
{
    public class Downloader
    {
        public int DownloadedSize { get; set; }
        public bool IsDownloadCompleted { get; set; }
        public bool IsDownloadStarted { get; set; }
        public int FileLenght { get; set; }
        public string FileName { get; set; }
        public string Url { get; set; }

        Thread thread = null;
        bool needStopThread = false;

        public event EventHandler DownloadCompleted;
        public event EventHandler ConnectFailed;
        public event EventHandler Connected;

        private void Download()
        {
            if (FileLenght == 0 || DownloadedSize != FileLenght)
            {
                string dir = Path.GetDirectoryName(FileName);
                if (dir != "") Helper.CreateDirectory(dir);

                byte[] nbytes = new byte[512];
                Stream ns = null;
                int nreadsize = 0;
                FileStream fs = null;
                HttpWebRequest request = null;

                try
                {
                    fs = new FileStream(FileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite);
                    request = (HttpWebRequest)HttpWebRequest.Create(Url);
                    if (FileLenght == 0)
                    {
                        FileLenght = (int)request.GetResponse().ContentLength;
                        fs.Write(new byte[FileLenght], 0, FileLenght);

                        string s = "0\r\n0";
                        File.WriteAllText(FileName + ".cfg", s);
                    }
                    fs.Position = DownloadedSize;
                    request.AddRange(DownloadedSize);

                    ns = request.GetResponse().GetResponseStream();
                }
                catch
                {
                    OnConnectFailed();
                    fs.Close();
                    fs = null;
                    ns = null;
                    needStopThread = false;
                    thread = null;
                    return;
                }


                if (Connected != null) Connected(this, EventArgs.Empty);

                do
                {
                    try
                    {
                        if (needStopThread) break;
                        if (fs != null)
                        {
                            nreadsize = ns.Read(nbytes, 0, 512);
                            fs.Write(nbytes, 0, nreadsize);
                            fs.Flush();
                            DownloadedSize += nreadsize;
                        }
                    }
                    catch (ThreadAbortException) { break; }
                    catch (Exception) { OnConnectFailed(); }
                } while (nreadsize > 0);

                request.Abort();
                ns.Close();
                fs.Close();
                fs = null;
                ns = null;
            }

            needStopThread = false;
            thread = null;

            try { OnDownloadCompleted(); }
            catch { OnDownloadCompleted(); }
        }

        private void OnConnectFailed()
        {
            IsDownloadCompleted = true;
            IsDownloadStarted = false;
            if (ConnectFailed != null) ConnectFailed(this, EventArgs.Empty);
        }

        private void OnDownloadCompleted()
        {
            IsDownloadStarted = false;
            if (DownloadedSize == FileLenght)
            {
                if (File.Exists(FileName + ".cfg")) File.Delete(FileName + ".cfg");
                if (DownloadCompleted != null) DownloadCompleted(this, EventArgs.Empty);
                IsDownloadCompleted = true;
            }
            else
            {
                string s = DownloadedSize.ToString() + "\r\n" + FileLenght.ToString();
                File.WriteAllText(FileName + ".cfg", s);
            }
        }

        public void Start()
        {
            if (File.Exists(FileName + ".cfg"))
            {
                string[] s = File.ReadAllText(FileName + ".cfg").Split(new string[] { "\r\n" }, StringSplitOptions.None);
                Start(int.Parse(s[0]), int.Parse(s[1]));
            }
            else if (File.Exists(FileName) && !File.Exists(FileName + ".cfg"))
            {
                FileInfo fi = new FileInfo(FileName);
                Start((int)fi.Length, (int)fi.Length);
            }
            else Start(0, 0);
        }

        public void Start(int startByte, int fileLenght)
        {
            if (IsDownloadStarted)
            {
                int i = 1;
                while (IsDownloadStarted && thread != null)
                {
                    if (i % 100 == 0) thread.Abort();
                    if (i % 1000 == 0) break;
                    needStopThread = true;
                    i++;
                }
            }

            needStopThread = false;
            IsDownloadCompleted = false;
            DownloadedSize = startByte;
            FileLenght = fileLenght;
            thread = new Thread(new ThreadStart(Download));
            thread.Start();
            IsDownloadStarted = true;
        }

        public void Stop()
        {
            needStopThread = true;
        }
    }
}